package com.minesweeper;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

@FunctionalInterface
interface GameOverListener {
    void onGameOver(boolean isWin);
}

public class GameBoard {
    private final int rows;
    private final int cols;
    private final int mines;
    private final Difficulty difficulty;
    private boolean[][] minesArray;
    private int[][] numbers;
    private boolean[][] flagged;
    private boolean[][] revealed;
    private int remainingMines;
    private boolean gameOver = false;
    private List<GameOverListener> gameOverListeners = new ArrayList<>();

    public GameBoard(Difficulty difficulty) {
        this.difficulty = difficulty;
        this.rows = difficulty.getRows();
        this.cols = difficulty.getCols();
        this.mines = difficulty.getMines();
        this.remainingMines = mines;
        initializeGame();
    }

    private void initializeGame() {
        minesArray = new boolean[rows][cols];
        numbers = new int[rows][cols];
        flagged = new boolean[rows][cols];
        revealed = new boolean[rows][cols];

        Random random = new Random();
        int minesPlaced = 0;
        while (minesPlaced < mines) {
            int row = random.nextInt(rows);
            int col = random.nextInt(cols);
            if (!minesArray[row][col]) {
                minesArray[row][col] = true;
                minesPlaced++;
            }
        }

        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                numbers[i][j] = countAdjacentMines(i, j);
            }
        }
    }

    private int countAdjacentMines(int row, int col) {
        int count = 0;
        for (int i = Math.max(row - 1, 0); i <= Math.min(row + 1, rows - 1); i++) {
            for (int j = Math.max(col - 1, 0); j <= Math.min(col + 1, cols - 1); j++) {
                if (minesArray[i][j]) {
                    count++;
                }
            }
        }
        return count;
    }

    public void handleClick(int row, int col) {
        if (gameOver || flagged[row][col] || revealed[row][col]) {
            return;
        }

        if (minesArray[row][col]) {
            gameOver = true;
            revealAllMines();
            notifyGameOver(false);
        } else {
            revealCell(row, col);
            if (checkWin()) {
                gameOver = true;
                notifyGameOver(true);
            }
        }
    }

    public void handleRightClick(int row, int col) {
        if (gameOver || revealed[row][col]) {
            return;
        }
        if (flagged[row][col]) {
            flagged[row][col] = false;
            remainingMines++;
        } else {
            flagged[row][col] = true;
            remainingMines--;
        }
    }

    private void revealCell(int row, int col) {
        if (row < 0 || row >= rows || col < 0 || col >= cols || flagged[row][col] || revealed[row][col]) {
            return;
        }

        revealed[row][col] = true;
        if (numbers[row][col] > 0) {
            // 这里可以添加更新界面显示数字的逻辑
        } else {
            for (int i = Math.max(row - 1, 0); i <= Math.min(row + 1, rows - 1); i++) {
                for (int j = Math.max(col - 1, 0); j <= Math.min(col + 1, cols - 1); j++) {
                    revealCell(i, j);
                }
            }
        }
    }

    private void revealAllMines() {
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (minesArray[i][j]) {
                    revealed[i][j] = true; // 揭示所有地雷
                }
            }
        }
    }

    private boolean checkWin() {
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (!minesArray[i][j] && !revealed[i][j]) {
                    return false;
                }
            }
        }
        return true;
    }

    public void addGameOverListener(GameOverListener listener) {
        gameOverListeners.add(listener);
    }

    private void notifyGameOver(boolean isWin) {
        for (GameOverListener listener : gameOverListeners) {
            listener.onGameOver(isWin);
        }
    }

    public int getRows() {
        return rows;
    }

    public int getCols() {
        return cols;
    }

    public int getRemainingMines() {
        return remainingMines;
    }

    public Difficulty getDifficulty() {
        return difficulty;
    }

    public boolean isRevealed(int row, int col) {
        return revealed[row][col];
    }

    public int getNumber(int row, int col) {
        return numbers[row][col];
    }

    public boolean isMine(int row, int col) {
        return minesArray[row][col];
    }

    public boolean isFlagged(int row, int col) {
        return flagged[row][col];
    }
}